﻿using System;
using System.Globalization;
using System.Messaging;
using System.Transactions;

namespace Lite.Messaging.Msmq
{
    internal class MsmqMessageQueue
        : IMessageQueue
    {
        private TimeSpan receiveTimeout = TimeSpan.FromMilliseconds(0);

        public MessageQueue MessageQueue
        {
            get;
            private set;
        }

        internal MsmqMessageQueue(MessageQueue messageQueue)
        {
            MessageQueue = messageQueue;
            MessageQueue.MessageReadPropertyFilter.CorrelationId = true;
        }

        private MessageQueueTransactionType DetermineTransactionType()
        {
            MessageQueueTransactionType transactionType = MessageQueueTransactionType.Automatic;

            if (MessageQueue.Transactional)
            {
                transactionType = Transaction.Current == null
                                    ? MessageQueueTransactionType.Single
                                    : MessageQueueTransactionType.Automatic;

            }
            else
                transactionType = MessageQueueTransactionType.None;

            return transactionType;
        }

        #region IMessageQueue Members

        public void Send(ISendMessage message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            MsmqMessage msmqMessage = message as MsmqMessage;

            if (msmqMessage == null)
            {
                throw new MessagingException(string.Format(CultureInfo.InvariantCulture, "Invalid message type: tried to send {0} but expecting {1}.", message.GetType(), typeof(MsmqMessage)));
            }

            MessageQueue.Send(msmqMessage.Message, DetermineTransactionType());
        }

        public IReceiveMessage Receive()
        {
            Message message;

            try
            {
                message = MessageQueue.Receive(this.receiveTimeout, DetermineTransactionType());
            }
            catch (MessageQueueException)
            {
                return null;
            }

            if (message == null)
                return null;
            else
                return MsmqMessageFactory.CreateMessage(message);
        }

        public IMessageFactory GetMessageFactory()
        {
            return new MsmqMessageFactory();
        }

        public bool CanSend(ISendMessage message)
        {
            return message is MsmqMessage;
        }

        public void Purge()
        {
            this.MessageQueue.Purge();
        }

        #endregion
    }
}
